/**
 * 
 */
package com.kingbi.util.dao.hibernate;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;

import org.apache.commons.beanutils.RowSetDynaClass;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.kingbi.util.dao.FindCmdDao;
import com.kingbi.util.dao.GenericDao;

/**
 * @author mouzb
 * 
 */
public class HibernateBaseDaoImpl<T, ID extends Serializable> extends HibernateDaoSupport implements
        GenericDao<T, ID>, FindCmdDao<T>
{
    private Class<T> persistentClass = null;

    /*
     * Cmd parameter is the named query's name. Please refer to Hibernate Named
     * Query.
     * 
     * @see com.zybedu.dao.FindCmdDao#findCmd(java.lang.String,
     *      java.lang.Object[], int, int)
     */
    @SuppressWarnings("unchecked")
    public List<T> findCmd(final String cmd, final Object[] params, final int page, final int count)
    {
        List<T> result = null;
        Object o = this.getHibernateTemplate().execute(new HibernateCallback()
        {
            public Object doInHibernate(Session session) throws HibernateException
            {

                Query query = session.getNamedQuery(cmd);
                if(params != null)
                {
                    int len = params.length;
                    for (int i = 0; i < len; i++)
                    {
                        query.setParameter(i, params[i]);
                    }
                }
                if(page > 0)
                {
                    int maxResult = count;
                    if(count < 1) maxResult = 1;
                    int first = (page - 1) * maxResult;
                    query.setFirstResult(first);
                    query.setMaxResults(maxResult + 1);
                }
                else
                {

                }
                List list = query.list();
                org.hibernate.Hibernate.initialize(list);
                return list;
            }
        });
        if(o != null) result = (List) o;
        return result;
    }

    public void delete(T entity)
    {
        this.getHibernateTemplate().delete(entity);
        this.getSession().flush();
    }

    @SuppressWarnings("unchecked")
    public List<T> findAll()
    {
        List list = this.getHibernateTemplate().loadAll(this.getPersistentClass());
        org.hibernate.Hibernate.initialize(list);
        return list;
    }

    @SuppressWarnings("unchecked")
    public List<T> findByExample(T exampleInstance, String[] excludeProperty)
    {
        //
        return this.getHibernateTemplate().findByExample(exampleInstance);
    }

    @SuppressWarnings("unchecked")
    public T findById(ID id)
    {
        return (T) this.getHibernateTemplate().get(this.getPersistentClass(), id);
    }

    public T save(T entity)
    {
        this.getHibernateTemplate().saveOrUpdate(entity);
        return entity;
    }
    
    public T add(T entity)
    {
        this.getHibernateTemplate().save(entity);
        return entity;
    }
    
    public T update(T entity)
    {
        this.getHibernateTemplate().update(entity);
        return entity;
    }

    public T add_update(T entity)
    {
        entity = (T) this.getHibernateTemplate().merge(entity);
        this.getHibernateTemplate().saveOrUpdate(entity);

        return entity;
    }

    @SuppressWarnings("unchecked")
    protected Class<T> getPersistentClass()
    {
        if(this.persistentClass == null)
        {
            this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                    .getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return this.persistentClass;
    }

    public Long getCountByHQL(final String queryStr, final Object[] params)
    {
        Long result = null;
        Object obj = this.getHibernateTemplate().execute(new HibernateCallback()
        {

            public Object doInHibernate(Session session) throws HibernateException
            {

                Query query = session.createQuery(queryStr);
                if(params != null)
                {
                    int len = params.length;
                    for (int i = 0; i < len; i++)
                    {
                        query.setParameter(i, params[i]);
                    }
                }

                return query.uniqueResult();
            }
        });
        if(obj != null)
        {
            result = (Long) obj;
        }

        return result;
    }

    public List<T> findByHQL(final String queryStr, final Object[] params, final int start,
            final int max)
    {
        List<T> result = null;
        Object obj = this.getHibernateTemplate().execute(new HibernateCallback()
        {

            public Object doInHibernate(Session session) throws HibernateException
            {

                Query query = session.createQuery(queryStr);
                if(params != null)
                {
                    int len = params.length;
                    for (int i = 0; i < len; i++)
                    {
                        query.setParameter(i, params[i]);
                    }
                }
                if(start > 0)
                {
                    int maxResult = max;
                    if(maxResult < 1)
                    {
                        maxResult = 10;
                    }
                    query.setFirstResult(start - 1);
                    query.setMaxResults(maxResult);
                }
                List list = query.list();
                org.hibernate.Hibernate.initialize(list);
                return list;
            }
        });
        if(obj != null)
        {
            result = (List<T>) obj;
        }

        return result;
    }

    public boolean delteByHQL(final String queryStr, final Object[] params)
    {
        Object obj = this.getHibernateTemplate().execute(new HibernateCallback()
        {
            public Object doInHibernate(Session session) throws HibernateException
            {

                Query query = session.createQuery(queryStr);
                if(params != null)
                {
                    int len = params.length;
                    for (int i = 0; i < len; i++)
                    {
                        query.setParameter(i, params[i]);
                    }
                }

                int result = query.executeUpdate();
                if(result > 0)
                    return true;
                else
                    return false;
            }
        });
        if(obj != null) return (Boolean) obj;
        return false;
    }

    /**
     * 
     * 
     * 
     * /*Query query = session.createQuery("select * from p_dept"); if (params !=
     * null) { int len = params.length; for (int i = 0; i < len; i++) {
     * query.setParameter(i, params[i]); } } ScrollableResults rs =
     * query.scroll(); int rowCount = rs.getRowNumber(); List<Object[]> list =
     * new ArrayList<Object[]>(); Object[] obj = null; while (rs.next()) { obj =
     * new Object[rowCount]; for (int i = 0; i < rowCount; i++) { obj[i] =
     * rs.get(i); } list.add(obj); } return list;
     */
    @SuppressWarnings("unchecked")
    public List<Object> findBySQL(final String qeurySql, final Object[] params) throws SQLException
    {
        ResultSet rs = null;
        PreparedStatement ps = null;
        List<Object> result = null;
        Connection conn = null;
        try
        {
            conn = this.getSession().connection();
            ps = conn.prepareStatement(qeurySql);
            if(params != null)
            {
                for (int i = 0; i < params.length; i++)
                {
                    Object param = params[i];
                    ps.setObject(i + 1, param);
                }
            }
            rs = ps.executeQuery();

            result = new RowSetDynaClass(rs).getRows();

        }
        catch (SQLException ex)
        {
            throw new SQLException("查询数据库异常");
        }
        finally
        {
            rs.close();
            ps.close();
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    public List<Object> findBySQL(final String qeurySql, final Object[] params, final int start,
            final int max) throws SQLException
    {
        ResultSet rs = null;
        PreparedStatement ps = null;
        List<Object> result = null;
        Connection conn = null;
        try
        {
            conn = this.getSession().connection();
            ps = conn.prepareStatement(qeurySql, ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
            if(params != null)
            {
                for (int i = 0; i < params.length; i++)
                {
                    Object param = params[i];
                    ps.setObject(i + 1, param);
                }
            }
            if(start > 0)
            {
                ps.setMaxRows(start + max-1);//标示一页显示多少条
            }
            rs = ps.executeQuery();
            if(start-1 > 0)
            {
                rs.absolute(start-1);//表示不是第一页从多少条开始显示
            }
            result = new RowSetDynaClass(rs).getRows();

        }
        catch (SQLException ex)
        {
            throw new SQLException("查询数据库异常");
        }
        finally
        {
            rs.close();
            ps.close();
        }
        return result;
    }
    
    public int exeSql(final String sql) throws SQLException {
    	int result = 0;
		PreparedStatement ps = null;
		Connection conn = null;
		try {
			conn = this.getSession().connection();
			ps = conn.prepareStatement(sql);
			result = ps.executeUpdate();
		} catch (SQLException ex) {
			throw new SQLException("executeUpdate 异常");
		} finally {
			ps.close();
		}
		return result;
	}
    
    public int deleteBySQL(final String sql) throws SQLException {
    	int result = 0;
		PreparedStatement ps = null;
		Connection conn = null;
		try {
			conn = this.getSession().connection();
			ps = conn.prepareStatement(sql);
			result = ps.executeUpdate();
		} catch (SQLException ex) {
			throw new SQLException("executeUpdate 异常");
		} finally {
			ps.close();
		}
		return result;
	}
    
    public void exeProcedure(String procString,List<Object> params) throws Exception {
        CallableStatement stmt = null;
        try {
            stmt = this.getSession().connection().prepareCall(procString);
            if (params != null){
                int idx = 1;
                for (Object obj : params) {
                    if (obj != null) {
                        stmt.setObject(idx, obj);
                    } else {
                        stmt.setNull(idx, Types.NULL);
                    }
                    idx++;
                }
            }
            stmt.execute();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new Exception("调用存储过程的时候发生错误[sql = " + procString + "]", e);
        } finally{
        	stmt.close();
        }
    }
    
    public List callProcedure(String procString,Object[] params) throws Exception {
    	List list = null;
    	Session session =this.getSession();
    	SQLQuery query = session.createSQLQuery(procString);
    	if(params != null){
    		for (int i = 0; i < params.length; i++)
            {
                Object param = params[i];
                query.setString(i, param.toString());
            }
    	}
    	list =query.list();
    	return list;
    }

}
